/**************************************************************************
Copyright (C) 2008-2010 United States Government. All rights reserved. 

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
****************************************************************************/
package rage


import grails.test.*
import groovy.util.slurpersupport.GPathResult
import org.codehaus.groovy.grails.commons.ConfigurationHolder;

import rage.GeoParserService.GeoType
import rage.filters.Filter
import rage.filters.StringFilter
import rage.Feed.FeedType

import java.util.Map;

class FeedControllerTests extends ControllerUnitTestCase {
	
	String feedTitle = "Example Feed"
	String feedDesc = "syndication feed description"
	String item1Title = "1"
	String item1Desc = "item 1 is about x"
	String item1Date = "2004-08-19T11:54:37-08:00"
	String item2Title = "2"
	String item2Desc = "item 2 is about y"
	String item2Date = "2004-08-19T11:54:37-08:00"
	
	protected void setUp() {
		super.setUp()

		//Set up mock for converterService
		def converterServiceMock = mockFor(ConverterService);
		converterServiceMock.demand.decodeParam(1..1) {String arg1 -> 
			return "http://localhost/site?this=a&that=b";
		};
		controller.converterService = converterServiceMock.createMock();
	}

	protected void tearDown() {
		super.tearDown()
	}

	void testKml() {
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 -> 
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 -> 
			Feed feed = new Feed();
			feed.title = feedName;
			feed.description = feedDescription;
			return feed
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";
		controller.params.color = "ff0000";

		Map returnMap = controller.kml();

		assertNotNull("Controller did not return map", returnMap);
		Feed feed = returnMap.feedInstance;
		assertNotNull("Controller map does not contain expected model object: 'feedInstance'", feed);
		assertEquals(feedName, feed.title);
		assertEquals(feedDescription, feed.description);

		String color = returnMap.feedColor;
		assertNotNull("Controller map does not contain expected model object: 'feedColor'", color);
		assertEquals(controller.params.color, color);
	}

	void testKml_no_url_param() {

		controller.params.color = "ff0000";
		controller.kml();

		assertNotNull(controller.flash);
		assertNotNull(controller.flash.message);
	}

	void testKml_no_color_param() {

		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock configuration
		String defaultColor = "00ff00";
		def mockedConfig = new ConfigObject();
		mockedConfig.rage.default.marker.color = defaultColor;
		ConfigurationHolder.config = mockedConfig;

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 -> 
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 -> 
			Feed feed = new Feed();
			feed.title = feedName;
			feed.description = feedDescription;
			return feed
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";

		Map returnMap = controller.kml();

		assertNotNull("Controller did not return map", returnMap);
		Feed feed = returnMap.feedInstance;
		assertNotNull("Controller map does not contain expected model object: 'feedInstance'", feed);
		assertEquals(feedName, feed.title);
		assertEquals(feedDescription, feed.description);

		String color = returnMap.feedColor;
		assertNotNull("Controller map does not contain expected model object: 'feedColor'", color);
		assertEquals(defaultColor, color);
	}

	void testKml_titleFilter_param() {
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 ->
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService, verify title filter sent to caller
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 ->
			assertNotNull("Filter list not expected to be null", arg2)
			assertEquals("Unexpected filter list size",
				1, arg2.size())
			StringFilter filter = arg2.get(0)
			assertNotNull("Filter not expected to be null", filter)
			assertEquals("Filter member field not set to expected value",
				StringFilter.Field.TITLE, filter.field)
			assertEquals("Filter member filterOperand not set to expected value",
				"hello", filter.filterOperand)
			assertEquals("Filter member operator not set to expected value",
				StringFilter.Operator.EQUALS, filter.operator)
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";
		controller.params.color = "ff0000";
		controller.params.title = "EQUALS_hello";

		Map returnMap = controller.kml();
	}
	
	void testKml_contentFilter_param() {
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 ->
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService, verify title filter sent to caller
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 ->
			assertNotNull("Filter list not expected to be null", arg2)
			assertEquals("Unexpected filter list size",
				1, arg2.size())
			StringFilter filter = arg2.get(0)
			assertNotNull("Filter not expected to be null", filter)
			assertEquals("Filter member field not set to expected value",
				StringFilter.Field.CONTENT, filter.field)
			assertEquals("Filter member filterOperand not set to expected value",
				"hello", filter.filterOperand)
			assertEquals("Filter member operator not set to expected value",
				StringFilter.Operator.EQUALS, filter.operator)
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";
		controller.params.color = "ff0000";
		controller.params.content = "EQUALS_hello";

		Map returnMap = controller.kml();
	}
	
	void testKml_numericalFilter_param() {
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 ->
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService, verify title filter sent to caller
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 ->
			assertNotNull("Filter list not expected to be null", arg2)
			assertEquals("Unexpected filter list size",
				1, arg2.size())
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";
		controller.params.color = "ff0000";
		controller.params.numerical = "TITLE_M_GREATERTHAN_3.0";

		Map returnMap = controller.kml();
	}
	
	void testKml_boundingBoxFilter_param() {
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";

		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 ->
			return [responsecode: 200, content: "feed xml..."]
		};
		controller.getService = getServiceMock.createMock();

		//Set up mock for feedParserService, verify title filter sent to caller
		def feedParserServiceMock = mockFor(FeedParserService);
		feedParserServiceMock.demand.parseFeed(2..2) {String arg1, List<Filter> arg2 ->
			assertNotNull("Filter list not expected to be null", arg2)
			assertEquals("Unexpected filter list size",
				1, arg2.size())
		};
		controller.feedParserService = feedParserServiceMock.createMock();

		controller.params.url = "http://localhost:8080/feed.atom";
		controller.params.color = "ff0000";
		controller.params.bbgeo = "-3.0,-2.0,-5.0,0.0";

		Map returnMap = controller.kml();
	}
	
	void testKml_get_error() {
		//Set up mock for getService
		def getServiceMock = mockFor(GetService);
		getServiceMock.demand.getFeed(1..1) {String arg1, String arg2, String arg3 -> 
			return [responsecode: 404, responsemessage: "not found"]
		};
		controller.getService = getServiceMock.createMock();

		controller.params.url = "http://localhost:8080/notfound";
		controller.params.color = "ff0000";

		controller.kml();

		assertNotNull(controller.flash);
		assertEquals("GET response[404]: not found", controller.flash.message);
	}
	
	void testConvert_Raw_Atom_To_Kml() {
     	// Set up mock for feedParserService
		def feedName = "feed";
		def feedDescription = "This Feed is the best!";
		def feedContent = '''<?xml version="1.0" encoding="utf-8"?>
								<feed xmlns="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss">
								
								  <title>Example Feed</title>
								  <subtitle>This Feed is the best!</subtitle>
								  <link href="http://example.org/"/>
								  <updated>2003-12-13T18:30:02Z</updated>
								  <author>
								    <name>John Doe</name>
								  </author>
								  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
								  <entry>
								    <title>Atom-Powered Robots Run Amok</title>
								    <link href="http://example.org/2003/12/13/atom03"/>
								    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
								    <updated>2003-12-13T18:30:02Z</updated>
								    <summary>Some text.</summary>
								    <georss:point>45.256 -71.92</georss:point>
								  </entry>
								
								</feed>'''
		
		def feedParserService = new FeedParserService()
		
		//Create mock for GeoParserService
		def geoParserServiceMock = mockFor(GeoParserService);
		geoParserServiceMock.demand.getGeoType(1..1) {String arg1 ->
			return GeoType.SIMPLE;
		}
		geoParserServiceMock.demand.parseGeometry(1..1) {GeoType arg1, GPathResult arg2 ->
			List<Geometry> geoList = []
			return geoList;
		};
		feedParserService.geoParserService = geoParserServiceMock.createMock();
		
		controller.feedParserService = feedParserService

		controller.params.content = feedContent;
		controller.params.url = "http://localhost:8080/notfound"
		controller.params.color = "ff0000";

		Map returnMap = controller.convert();
		assertNotNull("Controller did not return map", returnMap);
		
		Feed feed = returnMap.feedInstance;
		assertNotNull("Controller map does not contain expected model object: 'feedInstance'", feed);
		assertEquals("Example Feed", feed.title);
		assertEquals(feedDescription, feed.description);

		String color = returnMap.feedColor;
		assertNotNull("Controller map does not contain expected model object: 'feedColor'", color);
		assertEquals("ff0000", color);
	
	}
	
	void testConvert_Invalid_Get_Request() {
		// Test that calling controller with GET fails
		controller.request.method = "GET"
		controller.params.color = "ff0000"
		controller.convert()
		assert 405 == controller.response.status
	}
	
	void testConvert_POST_Content_To_Kml() {
		// Set up mock for feedParserService
		def feedName = "Example Feed"
		def feedDescription = "This Feed is the best!"
		def color = "ff0000"
		
		// Set up mock for feedParserService
		def feedParserServiceMock = mockFor(FeedParserService)
		Feed feed = new Feed()
		feed.title = feedName
		feed.description = feedDescription
		feed.type = FeedType.ATOM
		Placemark pmark = new Placemark(name: "sample place", description: "sample place description")
		Map<String, List<Placemark>> placemarks = ["mapkey":[pmark]]
		feed.placemarks = placemarks
		
		feedParserServiceMock.demand.parseFeed(1..1) { def arg1, def arg2 ->
			return feed
		}
		controller.feedParserService = feedParserServiceMock.createMock()
		
		controller.params.color = color
		controller.params.content = "<empty/>"
		
		Map returnMap = controller.convert()
		assertNotNull("Controller did not return valid map", returnMap)
		
		assert feed == this.controller.renderArgs["model"]."feedInstance"
		assert color == this.controller.renderArgs["model"]."feedColor"
		assert feedName == this.controller.renderArgs["model"].feedInstance.title
	}
	
	void testConvert_Valid_POST_But_Invalid_GeoRSS_Content() {
		def feedName = "Example Feed"
		def feedDescription = "This Feed is the best!"
		def color = "ff00000"
		
		// Set up mock for feedParserService
		def feedParserServiceMock = mockFor(FeedParserService)
		Feed feed = new Feed()
		feed.title = feedName
		feed.description = feedDescription
		feed.type = FeedType.ATOM
		
		feedParserServiceMock.demand.parseFeed(1..1) { def arg1, def arg2 ->
			return feed
		}
		
		controller.feedParserService = feedParserServiceMock.createMock()
		
		controller.params.color = color
		controller.convert()
		assert 415 == controller.response.status
	}
	
}
